﻿using NetJavap.JVM;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace NetJavap
{
    public static class JOpcodeBuilder
    {
        private static Dictionary<Byte, JOpcodeDefine> _opcodeDefs = new Dictionary<Byte, JOpcodeDefine>();

        public static JOpcode ReadOne(BinaryReader reader, JavaClass cls)
        {
            if (reader.BaseStream.Position >= reader.BaseStream.Length)
            {
                return null;
            }
            Byte opcode = reader.ReadByte();
            reader.BaseStream.Position--;
            JOpcodeDefine def = _opcodeDefs[opcode];
            return new JOpcode(reader, cls, def.Length, def.ExecuteAction);
        }

        public static String GetMnemonic(Byte opcode)
        {
            JOpcodeDefine def = _opcodeDefs[opcode];
            return def.Mnemonic;
        }

        static void AddOpcodeDef(Byte opCode, Byte len, String mnemonic, OpCodeExecuteAction opAction = null)
        {
            _opcodeDefs[opCode] = new JOpcodeDefine(opCode, len, mnemonic, opAction);
        }
        static JOpcodeBuilder()
        {
            AddOpcodeDef(0x32, 0, "aaload", (runner) => runner
                .LoadArrayValue<Object>(
                    runner.PopOperateStackVar<Int32>(),
                    runner.PopOperateStackVar<ArrayJavaObject>())
                .IncrementPC());
            AddOpcodeDef(0x53, 0, "aastore", (runner) => runner
                .StoreArrayValue<Object>(
                    runner.PopOperateStackVar<Object>(),
                    runner.PopOperateStackVar<Int32>(),
                    runner.PopOperateStackVar<ArrayJavaObject>())
                .IncrementPC());
            AddOpcodeDef(0x01, 0, "aconst_null", (runner) => runner
                .PushVarToOperateStack<Object>(null)
                .IncrementPC());
            AddOpcodeDef(0x19, 1, "aload", (runner) => runner
                .LoadToOperateStack<Object>(runner.CurrentOpcode.GetByteValue())
                .IncrementPC());
            AddOpcodeDef(0x2a, 0, "aload_0", (runner) => runner
                .LoadToOperateStack<Object>(0)
                .IncrementPC());
            AddOpcodeDef(0x2b, 0, "aload_1", (runner) => runner
                .LoadToOperateStack<Object>(1)
                .IncrementPC());
            AddOpcodeDef(0x2c, 0, "aload_2", (runner) => runner
                .LoadToOperateStack<Object>(2)
                .IncrementPC());
            AddOpcodeDef(0x2d, 0, "aload_3", (runner) => runner
                .LoadToOperateStack<Object>(3)
                .IncrementPC());
            AddOpcodeDef(0xbd, 2, "anewarry", (runner) => runner
                .NewClassArrayInstance(
                    runner.CurrentOpcode.GetUInt16Value(),
                    runner.PopOperateStackVar<Int32>())
                .IncrementPC());
            AddOpcodeDef(0xb0, 0, "areturn", (runner) => runner
                .Return<Object>());
            AddOpcodeDef(0xbe, 0, "arraylength", (runner) => runner
                .ArrayLength(runner.PopOperateStackVar<ArrayJavaObject>())
                .IncrementPC());
            AddOpcodeDef(0x3a, 1, "astore", (runner) => runner
                .StoreToVarTable<Object>(runner.CurrentOpcode.GetByteValue())
                .IncrementPC());
            AddOpcodeDef(0x4b, 0, "astore_0", (runner) => runner
                .StoreToVarTable<Object>(0)
                .IncrementPC());
            AddOpcodeDef(0x4c, 0, "astore_1", (runner) => runner
                .StoreToVarTable<Object>(1)
                .IncrementPC());
            AddOpcodeDef(0x4d, 0, "astore_2", (runner) => runner
                .StoreToVarTable<Object>(2)
                .IncrementPC());
            AddOpcodeDef(0x4e, 0, "astore_3", (runner) => runner
                .StoreToVarTable<Object>(3)
                .IncrementPC());
            AddOpcodeDef(0xbf, 0, "athrow");
            AddOpcodeDef(0x33, 0, "baload", (runner) => runner
                .LoadArrayValue<Byte>(
                    runner.PopOperateStackVar<Int32>(),
                    runner.PopOperateStackVar<ArrayJavaObject>())
                .IncrementPC());
            AddOpcodeDef(0x54, 0, "bastore", (runner) => runner
                .StoreArrayValue<Byte>(
                    runner.PopOperateStackVar<Byte>(),
                    runner.PopOperateStackVar<Int32>(),
                    runner.PopOperateStackVar<ArrayJavaObject>())
                .IncrementPC());
            AddOpcodeDef(0x10, 1, "bipush", (runner) => runner
                .PushVarToOperateStack<Int32>(runner.CurrentOpcode.GetByteValue())
                .IncrementPC());
            AddOpcodeDef(0xca, 0, "breakpoint");
            AddOpcodeDef(0x34, 0, "caload", (runner) => runner
                .LoadArrayValue<Char>(
                    runner.PopOperateStackVar<Int32>(),
                    runner.PopOperateStackVar<ArrayJavaObject>())
                .IncrementPC());
            AddOpcodeDef(0x55, 0, "castore", (runner) => runner
                .StoreArrayValue<Int32>(
                    runner.PopOperateStackVar<Int32>(),
                    runner.PopOperateStackVar<Int32>(),
                    runner.PopOperateStackVar<ArrayJavaObject>())
                .IncrementPC());
            AddOpcodeDef(0xc0, 2, "checkcast", (runner) => runner
                .CheckCast(runner.CurrentOpcode.GetUInt16Value())
                .IncrementPC());
            AddOpcodeDef(0x90, 0, "d2f", (runner) => runner
                .ConvertOperateStackTop<Double, Single>((before) => (Single)before)
                .IncrementPC()
                );
            AddOpcodeDef(0x8e, 0, "d2i", (runner) => runner
                .ConvertOperateStackTop<Double, Int32>((before) => (Int32)before)
                .IncrementPC()
                );
            AddOpcodeDef(0x8f, 0, "d2l", (runner) => runner
                .ConvertOperateStackTop<Double, Int64>((before) => (Int64)before)
                .IncrementPC()
                );
            AddOpcodeDef(0x63, 0, "dadd", (runner) => runner
                .BinaryOperator<Double>((left, right) => left + right)
                .IncrementPC());
            AddOpcodeDef(0x31, 0, "daload", (runner) => runner
                .LoadArrayValue<Double>(
                    runner.PopOperateStackVar<Int32>(),
                    runner.PopOperateStackVar<ArrayJavaObject>())
                .IncrementPC());
            AddOpcodeDef(0x52, 0, "dastore", (runner) => runner
                .StoreArrayValue<Double>(
                    runner.PopOperateStackVar<Double>(),
                    runner.PopOperateStackVar<Int32>(),
                    runner.PopOperateStackVar<ArrayJavaObject>())
                .IncrementPC());
            AddOpcodeDef(0x98, 0, "dcmpg", (runner) =>
            {
                Double first = runner.PopOperateStackVar<Double>();
                Double second = runner.PopOperateStackVar<Double>();
                if (first == Double.NaN || second == Double.NaN)
                {
                    runner.PushVarToOperateStack<Int32>(1);
                }
                else
                {
                    runner.PushVarToOperateStack<Int32>(first > second ? 1 : (first < second ? -1 : 0));
                }
                runner.IncrementPC();
            });
            AddOpcodeDef(0x97, 0, "dcmpl");
            AddOpcodeDef(0x0e, 0, "dconst_0", (runner) => runner
                .PushVarToOperateStack<Double>(0d)
                .IncrementPC());
            AddOpcodeDef(0x0f, 0, "dconst_1", (runner) => runner
                .PushVarToOperateStack<Double>(1d)
                .IncrementPC());
            AddOpcodeDef(0x6f, 0, "ddiv", (runner) => runner
                .BinaryOperator<Double>((left, right) => left / right)
                .IncrementPC());
            AddOpcodeDef(0x18, 1, "dload", (runner) => runner
                .LoadToOperateStack<Double>(runner.CurrentOpcode.GetByteValue())
                .IncrementPC());
            AddOpcodeDef(0x26, 0, "dload_0", (runner) => runner
                .LoadToOperateStack<Double>(0)
                .IncrementPC());
            AddOpcodeDef(0x27, 0, "dload_1", (runner) => runner
                .LoadToOperateStack<Double>(1)
                .IncrementPC());
            AddOpcodeDef(0x28, 0, "dload_2", (runner) => runner
                .LoadToOperateStack<Double>(2)
                .IncrementPC());
            AddOpcodeDef(0x29, 0, "dload_3", (runner) => runner
                .LoadToOperateStack<Double>(3)
                .IncrementPC());
            AddOpcodeDef(0x6b, 0, "dmul", (runner) => runner
                .BinaryOperator<Double>((left, right) => left * right)
                .IncrementPC());
            AddOpcodeDef(0x77, 0, "dneg", (runner) => runner
                .SingleOperator<Double>((num) => (-num))
                .IncrementPC());
            AddOpcodeDef(0x73, 0, "drem", (runner) => runner
                .BinaryOperator<Double>((left, right) => left % right)
                .IncrementPC());
            AddOpcodeDef(0xaf, 0, "dreturn", (runner) => runner
                .Return<Double>());
            AddOpcodeDef(0x39, 1, "dstore", (runner) => runner
                .StoreToVarTable<Double>(runner.CurrentOpcode.GetByteValue())
                .IncrementPC());
            AddOpcodeDef(0x47, 0, "dstore_0", (runner) => runner
                .StoreToVarTable<Double>(0)
                .IncrementPC());
            AddOpcodeDef(0x48, 0, "dstore_1", (runner) => runner
                .StoreToVarTable<Double>(1)
                .IncrementPC());
            AddOpcodeDef(0x49, 0, "dstore_2", (runner) => runner
                .StoreToVarTable<Double>(2)
                .IncrementPC());
            AddOpcodeDef(0x4a, 0, "dstore_3", (runner) => runner
                .StoreToVarTable<Double>(3)
                .IncrementPC());
            AddOpcodeDef(0x67, 0, "dsub", (runner) => runner
                .BinaryOperator<Double>((left, right) => left - right)
                .IncrementPC());
            AddOpcodeDef(0x59, 0, "dup", (runner) => runner
                .Dup()
                .IncrementPC());
            AddOpcodeDef(0x5a, 0, "dup_x1");
            AddOpcodeDef(0x5b, 0, "dip_x2");
            AddOpcodeDef(0x5c, 0, "dup2");
            AddOpcodeDef(0x5d, 0, "dup2_x1");
            AddOpcodeDef(0x5e, 0, "dup2_x2");
            AddOpcodeDef(0x8d, 0, "f2d", (runner) => runner
                .ConvertOperateStackTop<Single, Double>((before) => (Double)before)
                .IncrementPC()
                );
            AddOpcodeDef(0x8b, 0, "f2i", (runner) => runner
                .ConvertOperateStackTop<Single, Int32>((before) => (Int32)before)
                .IncrementPC()
                );
            AddOpcodeDef(0x8c, 0, "f2l", (runner) => runner
                .ConvertOperateStackTop<Single, Int64>((before) => (Int64)before)
                .IncrementPC()
                );
            AddOpcodeDef(0x62, 0, "fadd", (runner) => runner
                .BinaryOperator<Single>((left, right) => left + right)
                .IncrementPC());
            AddOpcodeDef(0x30, 0, "faload", (runner) => runner
                .LoadArrayValue<Single>(
                    runner.PopOperateStackVar<Int32>(),
                    runner.PopOperateStackVar<ArrayJavaObject>())
                .IncrementPC());
            AddOpcodeDef(0x51, 0, "fastore", (runner) => runner
                .StoreArrayValue<Single>(
                    runner.PopOperateStackVar<Single>(),
                    runner.PopOperateStackVar<Int32>(),
                    runner.PopOperateStackVar<ArrayJavaObject>())
                .IncrementPC());
            AddOpcodeDef(0x96, 0, "fcmpg", (runner) =>
            {
                Single first = runner.PopOperateStackVar<Single>();
                Single second = runner.PopOperateStackVar<Single>();
                if (first == Single.NaN || second == Single.NaN)
                {
                    runner.PushVarToOperateStack<Int32>(1);
                }
                else
                {
                    runner.PushVarToOperateStack<Int32>(first > second ? 1 : (first < second ? -1 : 0));
                }
                runner.IncrementPC();
            });
            AddOpcodeDef(0x95, 0, "fcmpl");
            AddOpcodeDef(0x0b, 0, "fconst_0", (runner) => runner
                .PushVarToOperateStack<Single>(0f)
                .IncrementPC());
            AddOpcodeDef(0x0c, 0, "fconst_1", (runner) => runner
                .PushVarToOperateStack<Single>(1f)
                .IncrementPC());
            AddOpcodeDef(0x0d, 0, "fconst_2", (runner) => runner
                .PushVarToOperateStack<Single>(2f)
                .IncrementPC());
            AddOpcodeDef(0x6e, 0, "fdiv", (runner) => runner
                .BinaryOperator<Single>((left, right) => left / right)
                .IncrementPC());
            AddOpcodeDef(0x17, 1, "fload", (runner) => runner
                .LoadToOperateStack<Single>(runner.CurrentOpcode.GetByteValue())
                .IncrementPC());
            AddOpcodeDef(0x22, 0, "fload_0", (runner) => runner
                .LoadToOperateStack<Single>(0)
                .IncrementPC());
            AddOpcodeDef(0x23, 0, "fload_1", (runner) => runner
                .LoadToOperateStack<Single>(1)
                .IncrementPC());
            AddOpcodeDef(0x24, 0, "fload_2", (runner) => runner
                .LoadToOperateStack<Single>(2)
                .IncrementPC());
            AddOpcodeDef(0x25, 0, "fload_3", (runner) => runner
                .LoadToOperateStack<Single>(3)
                .IncrementPC());
            AddOpcodeDef(0x6a, 0, "fmul", (runner) => runner
                .BinaryOperator<Single>((left, right) => left * right)
                .IncrementPC());
            AddOpcodeDef(0x76, 0, "feng");
            AddOpcodeDef(0x72, 0, "frem", (runner) => runner
                .BinaryOperator<Single>((left, right) => left % right)
                .IncrementPC());
            AddOpcodeDef(0xae, 0, "freturn", (runner) => runner
                .Return<Single>());
            AddOpcodeDef(0x38, 1, "fstore", (runner) => runner
                .StoreToVarTable<Single>(runner.CurrentOpcode.GetByteValue())
                .IncrementPC());
            AddOpcodeDef(0x43, 0, "fstore_0", (runner) => runner
                .StoreToVarTable<Single>(0)
                .IncrementPC());
            AddOpcodeDef(0x44, 0, "fstore_1", (runner) => runner
                .StoreToVarTable<Single>(1)
                .IncrementPC());
            AddOpcodeDef(0x45, 0, "fstore_2", (runner) => runner
                .StoreToVarTable<Single>(2)
                .IncrementPC());
            AddOpcodeDef(0x46, 0, "fstore_3", (runner) => runner
                .StoreToVarTable<Single>(3)
                .IncrementPC());
            AddOpcodeDef(0x66, 0, "fsub", (runner) => runner
                .BinaryOperator<Single>((left, right) => left - right)
                .IncrementPC());
            AddOpcodeDef(0xb4, 2, "getfield", (runner) => runner
                .GetField(runner.CurrentOpcode.GetUInt16Value())
                .IncrementPC());
            AddOpcodeDef(0xb2, 2, "getstatic", (runner) => runner
                .GetStaticValue(runner.CurrentOpcode.GetUInt16Value())
                .IncrementPC());
            AddOpcodeDef(0xa7, 2, "goto", (runner) => runner
                .Goto(runner.CurrentOpcode.GetInt16Value()));
            AddOpcodeDef(0xc8, 4, "goto_w");
            AddOpcodeDef(0x91, 0, "i2b", (runner) => runner
                .ConvertOperateStackTop<Int32, Byte>((before) => (Byte)before)
                .IncrementPC()
                );
            AddOpcodeDef(0x92, 0, "i2c", (runner) => runner
                .ConvertOperateStackTop<Int32, Char>((before) => (Char)before)
                .IncrementPC()
                );
            AddOpcodeDef(0x87, 0, "i2d", (runner) => runner
                .ConvertOperateStackTop<Int32, Double>((before) => (Double)before)
                .IncrementPC()
                );
            AddOpcodeDef(0x86, 0, "i2f", (runner) => runner
                .ConvertOperateStackTop<Int32, Single>((before) => (Single)before)
                .IncrementPC()
                );
            AddOpcodeDef(0x85, 0, "i2l", (runner) => runner
                .ConvertOperateStackTop<Int32, Int64>((before) => (Int64)before)
                .IncrementPC()
                );
            AddOpcodeDef(0x93, 0, "i2s", (runner) => runner
                .ConvertOperateStackTop<Int32, Int16>((before) => (Int16)before)
                .IncrementPC()
                );
            AddOpcodeDef(0x60, 0, "iadd", (runner) => runner
                .BinaryOperator<Int32>((left, right) => left + right)
                .IncrementPC());
            AddOpcodeDef(0x2e, 0, "iaload", (runner) => runner
                .LoadArrayValue<Int32>(
                    runner.PopOperateStackVar<Int32>(),
                    runner.PopOperateStackVar<ArrayJavaObject>())
                .IncrementPC());
            AddOpcodeDef(0x7e, 0, "iand", (runner) => runner
                .BinaryOperator<Int32>((left, right) => left & right)
                .IncrementPC());
            AddOpcodeDef(0x4f, 0, "iastore", (runner) => runner
                .StoreArrayValue<Int32>(
                    runner.PopOperateStackVar<Int32>(),
                    runner.PopOperateStackVar<Int32>(),
                    runner.PopOperateStackVar<ArrayJavaObject>())
                .IncrementPC());
            AddOpcodeDef(0x02, 0, "iconst_m1", (runner) => runner
                .PushVarToOperateStack<Int32>(-1)
                .IncrementPC());
            AddOpcodeDef(0x03, 0, "iconst_0", (runner) => runner
                .PushVarToOperateStack<Int32>(0)
                .IncrementPC());
            AddOpcodeDef(0x04, 0, "iconst_1", (runner) => runner
                .PushVarToOperateStack<Int32>(1)
                .IncrementPC());
            AddOpcodeDef(0x05, 0, "iconst_2", (runner) => runner
                .PushVarToOperateStack<Int32>(2)
                .IncrementPC());
            AddOpcodeDef(0x06, 0, "iconst_3", (runner) => runner
                .PushVarToOperateStack<Int32>(3)
                .IncrementPC());
            AddOpcodeDef(0x07, 0, "iconst_4", (runner) => runner
                .PushVarToOperateStack<Int32>(4)
                .IncrementPC());
            AddOpcodeDef(0x08, 0, "iconst_5", (runner) => runner
                .PushVarToOperateStack<Int32>(5)
                .IncrementPC());
            AddOpcodeDef(0x6c, 0, "idiv", (runner) => runner
                .BinaryOperator<Int32>((left, right) => left / right)
                .IncrementPC());
            AddOpcodeDef(0xa5, 2, "if_acmpeq");
            AddOpcodeDef(0xa6, 2, "if_acmpne");
            //============if条件跳转部分==============/
            //实现方式，取栈顶元素，通过比较函数作比较
            //关于 || runner.IncrementPC() == null 的解释：
            //runner.IncrementPC() == null恒为false，所以状态取决于第一个条件
            //第一个条件满足则后面的语句不会执行，否则会执行后面的语句
            //详细请见JVMCodeRunner.Goto定义
            AddOpcodeDef(0x9f, 2, "if_icmpeq", (runner) => runner
                .Goto(runner.CurrentOpcode.GetInt16Value(), () => runner
                    .PopOperateStackVar<Int32>() == runner.PopOperateStackVar<Int32>() || runner.IncrementPC() == null));
            AddOpcodeDef(0xa2, 2, "if_icmpge", (runner) => runner
                .Goto(runner.CurrentOpcode.GetInt16Value(), () => runner
                    .PopOperateStackVar<Int32>() <= runner.PopOperateStackVar<Int32>() || runner.IncrementPC() == null));
            AddOpcodeDef(0xa3, 2, "if_icmpgt", (runner) => runner
                .Goto(runner.CurrentOpcode.GetInt16Value(), () => runner
                    .PopOperateStackVar<Int32>() < runner.PopOperateStackVar<Int32>() || runner.IncrementPC() == null));
            AddOpcodeDef(0xa4, 2, "if_icmple", (runner) => runner
                .Goto(runner.CurrentOpcode.GetInt16Value(), () => runner
                    .PopOperateStackVar<Int32>() >= runner.PopOperateStackVar<Int32>() || runner.IncrementPC() == null));
            AddOpcodeDef(0xa1, 2, "if_icmplt", (runner) => runner
                .Goto(runner.CurrentOpcode.GetInt16Value(), () => runner
                    .PopOperateStackVar<Int32>() > runner.PopOperateStackVar<Int32>() || runner.IncrementPC() == null));
            AddOpcodeDef(0xa0, 2, "if_icmpne", (runner) => runner
                .Goto(runner.CurrentOpcode.GetInt16Value(), () => runner
                    .PopOperateStackVar<Int32>() != runner.PopOperateStackVar<Int32>() || runner.IncrementPC() == null));
            AddOpcodeDef(0x99, 2, "ifeq", (runner) => runner
                .Goto(runner.CurrentOpcode.GetInt16Value(), () => runner
                    .PopOperateStackVar<Int32>() == 0 || runner.IncrementPC() == null));
            AddOpcodeDef(0x9c, 2, "ifge", (runner) => runner
                .Goto(runner.CurrentOpcode.GetInt16Value(), () => runner
                    .PopOperateStackVar<Int32>() >= 0 || runner.IncrementPC() == null));
            AddOpcodeDef(0x9d, 2, "ifgt", (runner) => runner
                .Goto(runner.CurrentOpcode.GetInt16Value(), () => runner
                    .PopOperateStackVar<Int32>() > 0 || runner.IncrementPC() == null));
            AddOpcodeDef(0x9e, 2, "ifle", (runner) => runner
                .Goto(runner.CurrentOpcode.GetInt16Value(), () => runner
                    .PopOperateStackVar<Int32>() <= 0 || runner.IncrementPC() == null));
            AddOpcodeDef(0x9b, 2, "iflt", (runner) => runner
                .Goto(runner.CurrentOpcode.GetInt16Value(), () => runner
                    .PopOperateStackVar<Int32>() < 0 || runner.IncrementPC() == null));
            AddOpcodeDef(0x9a, 2, "ifne", (runner) => runner
                .Goto(runner.CurrentOpcode.GetInt16Value(), () => runner
                    .PopOperateStackVar<Int32>() != 0 || runner.IncrementPC() == null));
            AddOpcodeDef(0xc7, 2, "ifnonnulll", (runner) => runner
                .Goto(runner.CurrentOpcode.GetInt16Value(), () => runner
                    .PopOperateStackVar<Object>() != null || runner.IncrementPC() == null));
            AddOpcodeDef(0xc6, 2, "ifnull", (runner) => runner
                .Goto(runner.CurrentOpcode.GetInt16Value(), () => runner
                    .PopOperateStackVar<Object>() == null || runner.IncrementPC() == null));

            AddOpcodeDef(0x84, 2, "iinc", (runner) => runner
                .IncrementLocalVar(runner.CurrentOpcode.OtherBytes[0], (SByte)runner.CurrentOpcode.OtherBytes[1])
                .IncrementPC());
            AddOpcodeDef(0x15, 1, "iload", (runner) => runner
                .LoadToOperateStack<Int32>(runner.CurrentOpcode.GetByteValue())
                .IncrementPC());
            AddOpcodeDef(0x1a, 0, "iload_0", (runner) => runner
                .LoadToOperateStack<Int32>(0)
                .IncrementPC());
            AddOpcodeDef(0x1b, 0, "iload_1", (runner) => runner
                .LoadToOperateStack<Int32>(1)
                .IncrementPC());
            AddOpcodeDef(0x1c, 0, "iload_2", (runner) => runner
                .LoadToOperateStack<Int32>(2)
                .IncrementPC());
            AddOpcodeDef(0x1d, 0, "iload_3", (runner) => runner
                .LoadToOperateStack<Int32>(3)
                .IncrementPC());
            AddOpcodeDef(0xfe, 0, "impdep1");
            AddOpcodeDef(0xff, 0, "impdep2");
            AddOpcodeDef(0x68, 0, "imul", (runner) => runner
                .BinaryOperator<Int32>((left, right) => left * right)
                .IncrementPC());
            AddOpcodeDef(0x74, 0, "ineg", (runner) => runner
                .SingleOperator<Int32>((num) => (-num))
                .IncrementPC());
            AddOpcodeDef(0xc1, 2, "instanceof",(runner)=>runner
                .InstanceOf(runner.CurrentOpcode.GetUInt16Value())
                .IncrementPC());
            AddOpcodeDef(0xba, 4, "invokedynamic");
            AddOpcodeDef(0xb9, 4, "invokeinterface");
            AddOpcodeDef(0xb7, 2, "invokespecial", (runner) => runner
                .Invoke(runner.CurrentOpcode.GetUInt16Value(), false));
            AddOpcodeDef(0xb8, 2, "invokestatic", (runner) => runner
                .Invoke(runner.CurrentOpcode.GetUInt16Value(), true));
            AddOpcodeDef(0xb6, 2, "invokevirtual", (runner) => runner
                .Invoke(runner.CurrentOpcode.GetUInt16Value(), false));
            AddOpcodeDef(0x80, 0, "ior", (runner) => runner
                .BinaryOperator<Int32>((left, right) => left | right)
                .IncrementPC());
            AddOpcodeDef(0x70, 0, "irem", (runner) => runner
                .BinaryOperator<Int32>((left, right) => left % right)
                .IncrementPC());
            AddOpcodeDef(0xac, 0, "ireturn", (runner) => runner
                .Return<Int32>());
            AddOpcodeDef(0x78, 0, "ishl", (runner) => runner
                .BinaryOperator<Int32, Int32, Int32>((left, right) => left << right)
                .IncrementPC());
            AddOpcodeDef(0x7a, 0, "ishr", (runner) => runner
                .BinaryOperator<Int32, Int32, Int32>((left, right) => left >> right)
                .IncrementPC());
            AddOpcodeDef(0x36, 1, "istore", (runner) => runner
                .StoreToVarTable<Int32>(runner.CurrentOpcode.GetByteValue())
                .IncrementPC());
            AddOpcodeDef(0x3b, 0, "istore_0", (runner) => runner
                .StoreToVarTable<Int32>(0)
                .IncrementPC());
            AddOpcodeDef(0x3c, 0, "istore_1", (runner) => runner
                .StoreToVarTable<Int32>(1)
                .IncrementPC());
            AddOpcodeDef(0x3d, 0, "istore_2", (runner) => runner
                .StoreToVarTable<Int32>(2)
                .IncrementPC());
            AddOpcodeDef(0x3e, 0, "istore_3", (runner) => runner
                .StoreToVarTable<Int32>(3)
                .IncrementPC());
            AddOpcodeDef(0x64, 0, "isub", (runner) => runner
                .BinaryOperator<Int32>((left, right) => left - right)
                .IncrementPC());
            AddOpcodeDef(0x7c, 0, "iushr", (runner) => runner
                .BinaryOperator<Int32, Int32, Int32>((left, right) => (Int32)(Utils.RightMove(left, right)))
                .IncrementPC());
            AddOpcodeDef(0x82, 0, "ixor", (runner) => runner
                .BinaryOperator<Int32>((left, right) => left ^ right)
                .IncrementPC());
            AddOpcodeDef(0xa8, 2, "jsr");
            AddOpcodeDef(0xc9, 4, "jsr_w");
            AddOpcodeDef(0x8a, 0, "l2d", (runner) => runner
                .ConvertOperateStackTop<Int64, Double>((before) => (Double)before)
                .IncrementPC()
                );
            AddOpcodeDef(0x89, 0, "l2f", (runner) => runner
                .ConvertOperateStackTop<Int64, Single>((before) => (Single)before)
                .IncrementPC()
                );
            AddOpcodeDef(0x88, 0, "l2i", (runner) => runner
                .ConvertOperateStackTop<Int64, Int32>((before) => (Int32)before)
                .IncrementPC()
                );
            AddOpcodeDef(0x61, 0, "ladd", (runner) => runner
                .BinaryOperator<Int64>((left, right) => left + right)
                .IncrementPC());
            AddOpcodeDef(0x2f, 0, "laload", (runner) => runner
                .LoadArrayValue<Int64>(
                    runner.PopOperateStackVar<Int32>(),
                    runner.PopOperateStackVar<ArrayJavaObject>())
                .IncrementPC());
            AddOpcodeDef(0x7f, 0, "land", (runner) => runner
                .BinaryOperator<Int64>((left, right) => left & right)
                .IncrementPC());
            AddOpcodeDef(0x50, 0, "lastore", (runner) => runner
                .StoreArrayValue<Int64>(
                    runner.PopOperateStackVar<Int64>(),
                    runner.PopOperateStackVar<Int32>(),
                    runner.PopOperateStackVar<ArrayJavaObject>())
                .IncrementPC());
            AddOpcodeDef(0x94, 0, "lcmp", (runner) =>
            {
                Int64 first = runner.PopOperateStackVar<Int64>();
                Int64 second = runner.PopOperateStackVar<Int64>();
                runner.PushVarToOperateStack<Int32>(first > second ? 1 : (first < second ? -1 : 0))
                      .IncrementPC();
            });
            AddOpcodeDef(0x09, 0, "lconst_0", (runner) => runner
                .PushVarToOperateStack<Int64>(0L)
                .IncrementPC());
            AddOpcodeDef(0x0a, 0, "lconst_1", (runner) => runner
                .PushVarToOperateStack<Int64>(1L)
                .IncrementPC());
            AddOpcodeDef(0x12, 1, "ldc", (runner) => runner
                .PushVarToOperateStack(runner.GetConstantValue(runner.CurrentOpcode.GetByteValue()))
                .IncrementPC());
            AddOpcodeDef(0x13, 2, "ldc_w", (runner) => runner
                .PushVarToOperateStack(runner.GetConstantValue(runner.CurrentOpcode.GetUInt16Value()))
                .IncrementPC());
            AddOpcodeDef(0x14, 2, "ldc2_w", (runner) => runner
                .PushVarToOperateStack(runner.GetConstantValue(runner.CurrentOpcode.GetUInt16Value()))
                .IncrementPC());
            AddOpcodeDef(0x6d, 0, "ldiv", (runner) => runner
                .BinaryOperator<Int64>((left, right) => left / right)
                .IncrementPC());
            AddOpcodeDef(0x16, 1, "lload", (runner) => runner
                .LoadToOperateStack<Int64>(runner.CurrentOpcode.GetByteValue())
                .IncrementPC());
            AddOpcodeDef(0x1e, 0, "lload_0", (runner) => runner
                .LoadToOperateStack<Int64>(0)
                .IncrementPC());
            AddOpcodeDef(0x1f, 0, "lload_1", (runner) => runner
                .LoadToOperateStack<Int64>(1)
                .IncrementPC());
            AddOpcodeDef(0x20, 0, "lload_2", (runner) => runner
                .LoadToOperateStack<Int64>(2)
                .IncrementPC());
            AddOpcodeDef(0x21, 0, "lload_3", (runner) => runner
                .LoadToOperateStack<Int64>(3)
                .IncrementPC());
            AddOpcodeDef(0x69, 0, "lmul", (runner) => runner
                .BinaryOperator<Int64>((left, right) => left * right)
                .IncrementPC());
            AddOpcodeDef(0x75, 0, "lneg", (runner) => runner
                .SingleOperator<Int64>((num) => (-num))
                .IncrementPC());
            //AddOpcodeDef(0xab,,"lookupswitch");
            AddOpcodeDef(0x81, 0, "lor", (runner) => runner
                .BinaryOperator<Int64>((left, right) => left & right)
                .IncrementPC());
            AddOpcodeDef(0x71, 0, "lrem", (runner) => runner
                .BinaryOperator<Int64>((left, right) => left % right)
                .IncrementPC());
            AddOpcodeDef(0xad, 0, "lreturn", (runner) => runner
                .Return<Int64>());
            AddOpcodeDef(0x79, 0, "lshl");
            AddOpcodeDef(0x7b, 0, "lshr");
            AddOpcodeDef(0x37, 1, "lstore", (runner) => runner
                .StoreToVarTable<Int64>(runner.CurrentOpcode.GetByteValue())
                .IncrementPC());
            AddOpcodeDef(0x3f, 0, "lstore_0", (runner) => runner
                .StoreToVarTable<Int64>(0)
                .IncrementPC());
            AddOpcodeDef(0x40, 0, "lstore_1", (runner) => runner
                .StoreToVarTable<Int64>(1)
                .IncrementPC());
            AddOpcodeDef(0x41, 0, "lstore_2", (runner) => runner
                .StoreToVarTable<Int64>(2)
                .IncrementPC());
            AddOpcodeDef(0x42, 0, "lstore_3", (runner) => runner
                .StoreToVarTable<Int64>(3)
                .IncrementPC());
            AddOpcodeDef(0x65, 0, "lsub", (runner) => runner
                .BinaryOperator<Int64>((left, right) => left - right)
                .IncrementPC());
            AddOpcodeDef(0x7d, 0, "lushr", (runner) => runner
                .BinaryOperator<Int64, Int32, Int64>((left, right) => (Int64)(Utils.RightMove(left, right)))
                .IncrementPC());
            AddOpcodeDef(0x83, 0, "lxor", (runner) => runner
                .BinaryOperator<Int64>((left, right) => left ^ right)
                .IncrementPC());
            AddOpcodeDef(0xc2, 0, "monitorenter");
            AddOpcodeDef(0xc3, 0, "monitorexit");
            AddOpcodeDef(0xc5, 3, "multianewarray");
            AddOpcodeDef(0xbb, 2, "new", (runner) => runner.NewClassInstance(runner
                .CurrentOpcode.GetUInt16Value())
                .IncrementPC());
            AddOpcodeDef(0xbc, 1, "newarray", (runner) => runner
                .NewArrayInstance(runner.CurrentOpcode.GetByteValue(), runner.PopOperateStackVar<Int32>())
                .IncrementPC());
            AddOpcodeDef(0x00, 0, "nop", (runner) => runner
                .IncrementPC());
            AddOpcodeDef(0x57, 0, "pop");
            AddOpcodeDef(0x58, 0, "pop2");
            AddOpcodeDef(0xb5, 2, "putfield", (runner) => runner.PutField(runner
                .CurrentOpcode.GetUInt16Value(), runner.PopOperateStackVar())
                .IncrementPC());
            AddOpcodeDef(0xb3, 2, "putstatic", (runner) => runner
                .SetStaticValue(runner.CurrentOpcode.GetUInt16Value(), runner.PopOperateStackVar())
                .IncrementPC());
            AddOpcodeDef(0xa9, 1, "ret");
            AddOpcodeDef(0xb1, 0, "return", (runner) => runner
                .Return());
            AddOpcodeDef(0x35, 0, "saload", (runner) => runner
                .LoadArrayValue<Int16>(
                    runner.PopOperateStackVar<Int32>(),
                    runner.PopOperateStackVar<ArrayJavaObject>())
                .IncrementPC());
            AddOpcodeDef(0x56, 0, "sastore", (runner) => runner
                .StoreArrayValue<Int16>(
                    runner.PopOperateStackVar<Int16>(),
                    runner.PopOperateStackVar<Int32>(),
                    runner.PopOperateStackVar<ArrayJavaObject>())
                .IncrementPC());
            AddOpcodeDef(0x11, 2, "sipush", (runner) => runner
                .PushVarToOperateStack<Int32>(runner.CurrentOpcode.GetInt16Value())
                .IncrementPC());
            AddOpcodeDef(0x5f, 0, "swap");
            //AddOpcodeDef(0xaa,,"tableswitch");
            //AddOpcodeDef(0xc4,,"wide");
        }

    }
}
